package dmxGroupControl.transmitters;

import dmxGroupControl.StatusCode;

import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.UUID;

public class SACNTransmitter extends DMXTransmitter
{
    byte sequenceID = 0;
    UUID name;
    short universeID;
    String sourceName;
    DatagramSocket socket;
    InetAddress address;
    
    public SACNTransmitter(String address, short universeID, String sourceName, UUID uuid)
    {
        this.sourceName = sourceName;
        this.universeID = universeID;
        this.name = uuid;
        try
        {
            this.address = InetAddress.getByName(address);
            socket = new DatagramSocket();
            UpdateStatus(StatusCode.NOTHING_SENT);
            //socket = new DatagramSocket(new InetSocketAddress("127.0.0.1", 5568));
        }
        catch (SocketException|UnknownHostException e)
        {
            UpdateStatus(e);
            e.printStackTrace();
        }
    }
    
    @Override
    public void SendDMXInternal(byte[] data)
    {
        byte[] packet = GetSACNPacket(universeID, sourceName, name, sequenceID++, data);
        DatagramPacket datagram = new DatagramPacket(packet, packet.length, address, 5568);

        try
        {
            socket.send(datagram);
            /*byte[] buffer = new byte[packet.length];
            DatagramPacket test = new DatagramPacket(buffer, packet.length);

            socket.receive(test);

            byte[] receivedData = test.getData();

            DealWithPacket(receivedData);*/
            if(!AlreadyGreen())
            {
                UpdateStatus(StatusCode.DATA_SENT);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void close()
    {
    	enabled = false;
        socket.close();
    }

    @Override
    public String GetAddress()
    {
        return address.getHostAddress();
    }

    @Override
    public String GetType()
    {
        return "sacn";
    }

    private static void DealWithPacket(byte[] packet)
    {
        ByteBuffer buffer = ByteBuffer.wrap(packet);
        short preamble = buffer.getShort();
        short flags = buffer.getShort();
        byte[] packetIdentifier = new byte[12];
        buffer.get(packetIdentifier);
        short flagsAndLength1 = buffer.getShort();
        int vector1 = buffer.getInt();
        byte[] cid = new byte[16];
        buffer.get(cid);

        short flagsAndLength2 = buffer.getShort();
        int vector2 = buffer.getInt();
        byte[] sourceName = new byte[64];
        buffer.get(sourceName);
        byte priority = buffer.get();
        short reserved = buffer.getShort();
        byte sequenceNumber = buffer.get();
        byte options = buffer.get();
        short universe = buffer.getShort();

        short flagsAndLength3 = buffer.getShort();
        byte vector3 = buffer.get();
        byte addressTypeAndDataType = buffer.get();
        short firstPropertyAddress = buffer.getShort();
        short addressIncrement = buffer.getShort();
        short propertyValueCount = buffer.getShort();

        byte startCode = buffer.get();
        byte[] properties = new byte[propertyValueCount - 1];
        buffer.get(properties);

    }

    private static byte[] GetSACNPacket(short universeID, String sourceName, UUID name, byte sequenceID, byte[] data)
    {
        short totalLength = (short)(125 + data.length + 1);
        short flags = (0x7 << 12);
        short rlpLength = (short)(totalLength - 16);
        short framingLength = (short)(totalLength - 38);
        short dmpLength = (short)(totalLength - 115);
        ByteBuffer buffer = ByteBuffer.allocate(totalLength);
        
        byte priority = 100;
        
        try
        {
            // Root Layer
            buffer.putShort( (short)0x0010 ); // preamble
            buffer.putShort( (short)0x0000 ); // postamble
            buffer.put( new byte[] { 0x41, 0x53, 0x43, 0x2d, 0x45, 
                                             0x31, 0x2e, 0x31, 0x37, 0x00, 
                                             0x00, 0x00 }); // packet identifier
            buffer.putShort((short)(flags & rlpLength));
            buffer.putInt(0x00000004); //vector
            buffer.putLong(name.getMostSignificantBits());
            buffer.putLong(name.getLeastSignificantBits());
            
            // Framing Layer
            buffer.putShort((short)(flags & framingLength));
            buffer.putInt(0x00000002); //vector
            int currentPosition = buffer.position();
            buffer.put(sourceName.getBytes("UTF-8"));
            buffer.position(currentPosition + 64); // source name
            buffer.put(priority); // priority
            buffer.putShort((short)0); //reserved
            buffer.put(sequenceID); //sequence number
            buffer.put((byte)0); //options
            buffer.putShort(universeID); //universe ID
            
            // DMP layer
            buffer.putShort((short)(flags & dmpLength)); //flags and length
            buffer.put((byte)2); //vector
            buffer.put((byte)0xa1); //address type and data type
            buffer.putShort((short)0); //first property address
            buffer.putShort((short)1); //address increment
            buffer.putShort((short)(data.length + 1));
            buffer.put((byte)0x00);
            buffer.put(data);
            
            return buffer.array();
            
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return null;
        }
        
    }
    
    public UUID GetUUID()
    {
        return name;
    }

    public int GetID()
    {
        return universeID;
    }

    public String GetName()
    {
        return sourceName;
    }

    @Override
    public String toString()
    {
        return "sACN transmitter - [" + universeID + "] " + GetAddress();
    }
}
